Wesbos - Custom Video Player


완성본 예시

사실 요즘은 자체적으로 이렇게 동영상 플레이어를 구현하는 것이 아니라,
유튜브와 같은 플랫폼에 이미 업로드 되어있는 영상을 불러오는 형식을 더 자주 사용하기 때문에, 실용적인 챕터일까? 라는 생각을 하기도 했다.

하지만…
JS를 통해 CSS적인 요소를 컨트롤 하는 부분과 valueChange를 하는 등의 연습은 큰 도움이 됐던 것 같다.


로직

  1. 다양한 객체들 const로 정의
  2. 이벤트 리스너 (재생버튼, 프로그레스바, 볼륨바, 속도바, 스킵버튼)
  3. 재생 기능과 CSS 제어
  4. 프로그레스바 구현
  5. 볼륨 컨트롤 구현
  6. 속도 설정 구현
  7. 스킵버튼 구현

Const!!

💡 이번 챕터에선 정의해줘야 할 객체들이 많다….

1
2
3
4
5
6
7
const player = document.querySelector('.player');
const video = player.querySelector('.viewer');
const toggle = player.querySelector('.toggle');
const progress = player.querySelector('.progress');
const progressBar = player.querySelector('.progress__filled');
const skipButtons = player.querySelectorAll('[data-skip]');
const ranges = player.querySelectorAll('.player__slider');

이벤트리스너

💡 구현해야 할 기능들이 많기 때문에… 이벤트 또한 역시나 많다…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//재생&일시정지 버튼
toggle.addEventListener('click', pause);
toggle.addEventListener('click', updateButton);

//비디오 뷰어 내에 있는 버튼과 프로그레스바
video.addEventListener('click', pause);
video.addEventListener('click', updateButton);
video.addEventListener('timeupdate', handleProgress);

// 프로그레스바, 사운드, 속도 등등의 value값 제어를 위한 것
ranges.forEach((range) => range.addEventListener('mousemove', valueChange));
ranges.forEach((range) => range.addEventListener('change', valueChange));

//스킵버튼
skipButtons.forEach((button) => button.addEventListener('click', skip));

재생과 버튼 업데이트

💡 재생 버튼을 누르면 재생이 되고, 버튼 아이콘도 변경되어야 한다.

필자는 if문을 쓰는게 더 쉽고 간편할 것 같아서…
if문을 통해 재생 및 일시정지, 그리고 재생버튼 업데이트 기능을 구현해봤다.

❗ 재생버튼 뿐만 아니라, 유튜브와 같이 비디오 플레이어 화면을 클릭했을 때도 재생 또는 일시정지가 될 수 있도록 구현하기 위해 pause함수가 video와 toggle에도 작동할 수 있도록 이벤트리스너를 작성했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//puase함수
function pause() {
//비디오가 정지되어 있으면 플레이
if (video.paused) {
video.play();
}
//아니면 일시정지
else {
video.pause();
}
}

function updateButton() {
// 정지되어 있으면 재생 아이콘이,
if (video.paused) {
toggle.textContent = '►';
}
// 재생중이면 일시정지 아이콘이 나타나도록 설정
else {
toggle.textContent = '❚ ❚';
}
}

그 외 기능들

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 볼륨과 속도바
function valueChange() {
//volume or playBackRate = this.value가 되는 것!
video[this.name] = this.value;
}

function skip() {
video.currentTime += parseFloat(this.dataset.skip);
}

function scrub(e) {
video.currentTime = (e.offsetX / progress.offsetWidth) * video.duration;
}

function handleProgress() {
const percent = (video.currentTime / video.duration) * 100;
progressBar.style.flexBasis = `${percent}%`;
}

최종 완성 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
const player = document.querySelector('.player');
const video = player.querySelector('.viewer');
const toggle = player.querySelector('.toggle');
const progress = player.querySelector('.progress');
const progressBar = player.querySelector('.progress__filled');
const skipButtons = player.querySelectorAll('[data-skip]');
const ranges = player.querySelectorAll('.player__slider');

function pause() {
if (video.paused) {
video.play();
} else {
video.pause();
}
}

function updateButton() {
if (video.paused) {
toggle.textContent = '►';
} else {
toggle.textContent = '❚ ❚';
}
}

function valueChange() {
video[this.name] = this.value;
}

function skip() {
video.currentTime += parseFloat(this.dataset.skip);
}

function scrub(e) {
video.currentTime = (e.offsetX / progress.offsetWidth) * video.duration;
}

function handleProgress() {
const percent = (video.currentTime / video.duration) * 100;
progressBar.style.flexBasis = `${percent}%`;
}

toggle.addEventListener('click', pause);
toggle.addEventListener('click', updateButton);

video.addEventListener('click', pause);
video.addEventListener('click', updateButton);
video.addEventListener('timeupdate', handleProgress);

ranges.forEach((range) => range.addEventListener('mousemove', valueChange));
ranges.forEach((range) => range.addEventListener('change', valueChange));

skipButtons.forEach((button) => button.addEventListener('click', skip));

let mousedown = false;
progress.addEventListener('click', scrub);
progress.addEventListener('mouseup', (e) => mousedown && scrub(e));
progress.addEventListener('mousedown', () => (mousedown = true));
progress.addEventListener('mousemove', () => (mousedown = false));

Author

Hoonjoo

Posted on

2022-01-04

Updated on

2022-02-07

Licensed under

Comments